package moa.sequencestreams.generator;

import org.apache.commons.math.random.RandomDataImpl;

import moa.sequencestreams.generator.Taxonomy;
import java.util.Random;

public class ItemSet {
	private	  int nitems;		// number of items
	private	  Taxonomy tax;	// taxonomy (optional)
	private	  float[] cum_prob;	// cumulative probability
	private	  float[] tax_prob;	// cumulative probability of choosing a child


	public ItemSet(int pitems, Taxonomy ptax)
	{
		tax = null ;//new Taxonomy (ptax);
		nitems = pitems;
		RandomDataImpl rd = new RandomDataImpl();
	  int i, j;
	  

	  cum_prob = new float [nitems];
	  //if (!tax.equals(null))
	  if (tax != null)
	    tax_prob = new float [nitems];
	  else
	    tax_prob = null;
	  for (i = 0; i < nitems; i++)
	    cum_prob[i] = (float) rd.nextExponential(pitems);	// prob. that this pattern will be picked

	  if (tax != null) {			// weight(itm) += wieght(children)
	    // normalize probabilities for the roots and for children
	    normalize(cum_prob, 0, tax.num_roots()-1);
	    for (i = 0; i < nitems && tax.num_children(i) > 0; i++)
	      normalize(cum_prob, tax.first_child(i), tax.last_child(i));

	    // calulate cumulative probabilities for children
	    for (i = 0; i < nitems; i++)
	      tax_prob[i] = cum_prob[i];
	    for (i = 1; i < nitems; i++)
	      if (tax.num_children(i) > 0)
		for (j = tax.first_child(i); j < tax.last_child(i); j++)
		  tax_prob[j+1] += tax_prob[j];

	    // set real probabilities
	    for (i = tax.num_roots(); i < nitems; i++)
	      cum_prob[i] *= cum_prob[ tax.parent(i) ] * tax.depth_ratio();
	  }

	  // normalize probabilites (why -- see get_pat)
	  normalize(cum_prob, 0, nitems-1);
	  for (i = 1; i < nitems; i++)	// calulate cumulative probabilities
	    cum_prob[i] += cum_prob[i-1];
	}

/*
	ItemSet::~ItemSet()
	{
	  delete [] cum_prob;
	}*/


	//  normalize probabilities between low and high
	//
	public void normalize(float prob[], int low, int high)
	{
	  float tot;
	  int i;

	  // normalize probabilites
	  tot = 0;
	  for (i = low; i <= high; i++)
	    tot += prob[i];
	  for (i = low; i <= high; i++)
	    prob[i] /= tot;
	}


	// returns a pattern chosen at random
	//
	public int get_item()
	{ 
	  float r;
	  int i;
	  Random ran = new Random();
	  // find the desired pattern using cum_prob table
	  r = ran.nextFloat();
	  // want item i such that cum_prob[i-1] < r <= cum_prob[i];
	  i = (int) (r * nitems);			// guess location of item
	  i += (r-cum_prob[i]) * nitems;	// refine guess
	  if (i >= nitems)			// check boundaries
	    i = nitems-1;
	  if (i < 0)
	    i = 0;
	  while ( i < (nitems-1) && r > cum_prob[i] )	// find item
	    i++;
	  while ( i > 0 && r <= cum_prob[i-1] )
	    i--;
	  return i;
	};


	// if no taxonomy, returns itm
	//
	public int specialize(int itm)
	{
	  float r;
	  int i, nchildren;
	  int first, last;
	  Random ran = new Random();
	  
	  if (tax == null) 		// no taxonomy
	    return itm;

	  nchildren = tax.num_children(itm);
	  if (nchildren == 0)		// no children
	    return itm;  

	  first = tax.child(itm, 0);
	  last = tax.child(itm, nchildren-1);

	  // find the desired pattern using cum_prob table
	  r = ran.nextFloat();
	  i = (int) (first + r * nchildren);
	  if (i == last)
	    i--;
	  while ( i < last && r > tax_prob[i] )
	    i++;
	  while ( i > first && r < tax_prob[i-1] )
	    i--;
	  return specialize(i);
	}  


	public float weight(int itm)	// returns prob. of choosing item
	{
	  if (itm == 0)
	    return cum_prob[itm];
	  else
	    return cum_prob[itm] - cum_prob[itm-1];
	}

}
